#include<vector>
#include<mutex>
#include<condition_variable>
using namespace std;
class CycleQueue {
private:
	vector<int>data;
	int size;
	int front = 0, rear = 0;
	condition_variable cond1;
	condition_variable cond2;
	mutex mx;
public:
	CycleQueue(int sz) :data(sz + 1), size(sz+1) {}

	bool isEmpty() {
		return front == rear;
	}

	bool isFull() {
		return front == (rear + 1) % size;
	}

	void push(int val) {
		unique_lock<mutex> lock(mx);
		cond1.wait(lock, [&]() {return !isFull(); });
		data[rear] = val;
		rear = (rear + 1) % size;
		cond2.notify_one();
	}


	int pop() {
		unique_lock<mutex> lock(mx);
		cond2.wait(lock, [&]() {return !isEmpty(); });
		int val = data[front];
		front = (front + 1) % size;
		cond1.notify_one();
		return val;
	}
};

//class CycleQueue {
//private:
//	vector<int>data;
//	int size;
//	int front = 0, rear = 0;
//	condition_variable cond1;
//	condition_variable cond2;
//	mutex mx;
//public:
//	CycleQueue(int sz):data(size+1),size(sz){}
//
//	bool isEmpty() {
//		return front == rear;
//	}
//
//	bool isFull() {
//		return front == (rear + 1) % size;
//	}
//
//	void push(int val) {
//		unique_lock<mutex> lock(mx);
//		cond1.wait(lock, [&]() {return !isFull(); });
//		data[rear] = val;
//		rear = (rear + 1) % size;
//		cond2.notify_one();
//	}
//	
//	int pop() {
//		unique_lock<mutex> lock(mx);
//		cond2.wait(lock, [&]() {return !isEmpty(); });
//		int val = data[front];
//		front = (front + 1) % size;
//		cond1.notify_one();
//		return val;
//	}
//};